# 使用提醒:
# 1. xbot包提供软件自动化、数据表格、Excel、日志、AI等功能
# 2. package包提供访问当前应用数据的功能，如获取元素、访问全局变量、获取资源文件等功能
# 3. 当此模块作为流程独立运行时执行main函数
# 4. 可视化流程中可以通过"调用模块"的指令使用此模块

import hashlib
import os
import shutil
import time
import traceback
import uuid
import json
import platform
import xbot

import requests
import subprocess
from selenium import webdriver
from selenium.common import NoSuchElementException
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from mysql_utils import MysqlUtils
from xbot import print, sleep
from datetime import datetime, timedelta
from lxml import etree
from xbot import print, sleep
import requests
from bs4 import BeautifulSoup
import re


class AmzLogin:

    def __init__(self):
        self.is_windows = platform.system() == 'Windows'
        self.is_mac = platform.system() == 'Darwin'
        if not self.is_windows and not self.is_mac:
            print("webdriver/cdp只支持windows和mac操作系统")
            exit()
        if self.is_windows:
            self.driver_folder_path = r'D:\softwore\ziniao\webdriver'  # TODO 放置chromedriver的文件夹路径
            self.client_path = R'D:\software\SuperBrowser\SuperBrowser\starter.exe'  # TODO 客户端程序starter.exe的路径
        else:
            self.driver_folder_path = r'/Users/用户名/webdriver'  # TODO 放置chromedriver的文件夹路径
            self.client_path = R'ziniao'  # 客户端程序名称
        self.socket_port = 16851
        self.user_info = {
            "company": "山西爱创商贸",
            "username": "zidonghua",
            "password": "ZidONGhua12"
        }
        self.use_date = datetime.now()

    def judge_day_or_week(self, use_browser):
        # 判断文件是否存在于本地，如果存在则不需要重复获取

        judge_file_day = self.judge_move_file('每天', self.two_days_ago)
        day_format = (self.use_date - timedelta(days=self.use_date.weekday()) - timedelta(days=2)).strftime("%Y_%m_%d")
        file_name = "US_热门搜索词_简单_Week_{}.csv".format(day_format)
        file_path_default = os.path.join(self.folder_path_default, file_name)
        print(file_path_default)
        is_exist = os.path.exists(file_path_default)
        print(is_exist)
        print(self.use_date.weekday() == 0)
        if self.use_date.weekday() == 1 and not is_exist:
            return "每周"
        if judge_file_day:
            return "每天"

    def judge_move_file(self, reporting_range, date):
        """判断文件的下载情况并对文件进行移动

        Args:
            reporting_range: 下载周期（每天/每周）
            date: 下载某天文件的日期
        """

        if reporting_range == '每天':
            report = 'Day'
        elif reporting_range == '每周':
            report = 'Week'
        year_ = date.split('/')[0]
        month_ = date.split('/')[1]
        day_ = date.split('/')[2]
        file_name = f'US_热门搜索词_简单_{report}_{year_}_{month_}_{day_}.csv'

        # 完整的文件路径
        file_path_default = os.path.join(self.folder_path_default, file_name)
        file_path_Transfer = os.path.join(self.folder_path_Transfer, file_name)

        if os.path.isfile(file_path_default):
            print("删除已有文件")
            os.remove(file_path_default)
            return 1
        else:
            print(f"当前日期的文件({reporting_range})还未下载，需要先进行下载")
            return 1

    def get_browser_list(self) -> list:
        request_id = str(uuid.uuid4())
        data = {
            "action": "getBrowserList",
            "requestId": request_id
        }
        data.update(self.user_info)

        r = self.send_http(data)
        if str(r.get("statusCode")) == "0":
            return r.get("browserList")
        elif str(r.get("statusCode")) == "-10003":
            print(f"login Err {json.dumps(r, ensure_ascii=False)}")
            exit()
        else:
            print(f"Fail {json.dumps(r, ensure_ascii=False)} ")
            exit()

    def update_core(self):
        """
        下载所有内核，打开店铺前调用，需客户端版本5.285.7以上
        因为http有超时时间，所以这个action适合循环调用，直到返回成功
        """
        data = {
            "action": "updataCore",
            "requestId": str(uuid.uuid4()),
        }
        data.update(self.user_info)
        while True:
            result = self.send_http(data)
            if result is None:
                print("等待客户端启动...")
                time.sleep(2)
                continue
            if result.get("statusCode") is None or result.get("statusCode") == -10003:
                print("当前版本不支持此接口，请升级客户端")
                return
            elif result.get("statusCode") == 0:
                return
            else:
                print(f"等待更新内核: {json.dumps(result)}")
                time.sleep(2)

    def send_http(self, data):
        """
        通讯方式
        :param data:
        :return:
        """
        try:
            url = 'http://127.0.0.1:{}'.format(self.socket_port)
            response = requests.post(url, json.dumps(data).encode('utf-8'), timeout=120)
            return json.loads(response.text)
        except Exception as err:
            print(err)

    def start_browser(self):
        """
        启动客户端
        """
        try:
            if self.is_windows:
                cmd = [self.client_path, '--run_type=web_driver', '--ipc_type=http', '--port=' + str(self.socket_port)]
            elif self.is_mac:
                cmd = ['open', '-a', self.client_path, '--args', '--run_type=web_driver', '--ipc_type=http',
                       '--port=' + str(self.socket_port)]
            else:
                exit()
            print(cmd)
            subprocess.Popen(cmd)
            time.sleep(5)
        except Exception:
            print('start browser process failed: ' + traceback.format_exc())
            exit()

    def kill_process(self):
        """
        终止紫鸟客户端已启动的进程
        """
        # 确认是否继续
        # confirmation = input("在启动之前，需要先关闭紫鸟浏览器的主进程，确定要终止进程吗？(y/n): ")
        # if confirmation.lower() == 'y':
        if self.is_windows:
            os.system('taskkill /f /t /im SuperBrowser.exe')
        elif self.is_mac:
            os.system('killall ziniao')
            time.sleep(3)

    def download_driver(self):
        if self.is_windows:
            config_url = "https://cdn-superbrowser-attachment.ziniao.com/webdriver/exe_32/config.json"
        elif self.is_mac:
            arch = platform.machine()
            if arch == 'x86_64':
                config_url = "https://cdn-superbrowser-attachment.ziniao.com/webdriver/mac/x64/config.json"
            elif arch == 'arm64':
                config_url = "https://cdn-superbrowser-attachment.ziniao.com/webdriver/mac/arm64/config.json"
            else:
                return
        else:
            return
        response = requests.get(config_url)
        # 检查请求是否成功
        if response.status_code == 200:
            # 获取文本内容
            txt_content = response.text
            config = json.loads(txt_content)
        else:
            print(f"下载驱动失败，状态码：{response.status_code}")
            exit()
        if not os.path.exists(self.driver_folder_path):
            os.makedirs(self.driver_folder_path)

        # 获取文件夹中所有chromedriver文件
        driver_list = [filename for filename in os.listdir(self.driver_folder_path) if
                       filename.startswith('chromedriver')]

        for item in config:
            filename = item['name']
            if self.is_windows:
                filename = filename + ".exe"
            local_file_path = os.path.join(self.driver_folder_path, filename)
            if filename in driver_list:
                # 判断sha1是否一致
                file_sha1 = self.encrypt_sha1(local_file_path)
                if file_sha1 == item['sha1']:
                    pass
                else:
                    print(f"驱动{filename}的sha1不一致，重新下载...")
                    self.download_file(item['url'], local_file_path)
                    # mac首次下载修改文件权限
                    if self.is_mac:
                        cmd = ['chmod', '+x', local_file_path]
                        subprocess.Popen(cmd)
            else:
                print(f"驱动{filename}不存在，开始下载...")
                self.download_file(item['url'], local_file_path)
                # mac首次下载修改文件权限
                if self.is_mac:
                    cmd = ['chmod', '+x', local_file_path]
                    subprocess.Popen(cmd)

    def encrypt_sha1(self, fpath: str) -> str:
        with open(fpath, 'rb') as f:
            return hashlib.new('sha1', f.read()).hexdigest()

    def download_file(self, url, save_path):
        # 发送GET请求获取文件内容
        response = requests.get(url, stream=True)
        # 检查请求是否成功
        if response.status_code == 200:
            # 创建一个本地文件并写入下载的内容（如果文件已存在，将被覆盖）
            with open(save_path, 'wb') as f:
                for chunk in response.iter_content(chunk_size=1024):
                    if chunk:
                        f.write(chunk)
            print(f"文件已成功下载并保存到：{save_path}")
        else:
            print(f"下载失败，响应状态码为：{response.status_code}")

    def open_store(self, store_info, isWebDriverReadOnlyMode=0, isprivacy=0, isHeadless=0, cookieTypeSave=0, jsInfo=""):
        request_id = str(uuid.uuid4())
        data = {
            "action": "startBrowser"
            , "isWaitPluginUpdate": 0
            , "isHeadless": isHeadless
            , "requestId": request_id
            , "isWebDriverReadOnlyMode": isWebDriverReadOnlyMode
            , "cookieTypeLoad": 0
            , "cookieTypeSave": cookieTypeSave
            , "runMode": "1"
            , "isLoadUserPlugin": False
            , "pluginIdType": 1
            , "privacyMode": isprivacy
            , "windowRatio": 70  # 打开的浏览器窗口尺寸 值范围：0-100，0不控制 100 全屏
            , "notPromptForDownload": 1  # 1 不弹，0：弹  下载文件的时候是否弹窗提示选择文件保存路径
        }
        data.update(self.user_info)

        if store_info.isdigit():
            data["browserId"] = store_info
        else:
            data["browserOauth"] = store_info
        if len(str(jsInfo)) > 2:
            data["injectJsInfo"] = json.dumps(jsInfo)

        r = self.send_http(data)
        if str(r.get("statusCode")) == "0":
            return r
        elif str(r.get("statusCode")) == "-10003":
            print(f"login Err {json.dumps(r, ensure_ascii=False)}")
            exit()
        else:
            print(f"Fail {json.dumps(r, ensure_ascii=False)} ")
            exit()

    def get_driver(self, open_ret_json):
        core_type = open_ret_json.get('core_type')
        if core_type == 'Chromium' or core_type == 0:
            major = open_ret_json.get('core_version').split('.')[0]
            if self.is_windows:
                chrome_driver_path = os.path.join(self.driver_folder_path, 'chromedriver%s.exe') % major
            else:
                chrome_driver_path = os.path.join(self.driver_folder_path, 'chromedriver%s') % major
            port = open_ret_json.get('debuggingPort')
            options = webdriver.ChromeOptions()
            options.add_argument('--log-level=3')
            options.add_experimental_option("debuggerAddress", '127.0.0.1:' + str(port))
            return webdriver.Chrome(service=Service(chrome_driver_path), options=options)
        else:
            return None

    def close_store(self, browser_oauth):
        request_id = str(uuid.uuid4())
        data = {
            "action": "stopBrowser"
            , "requestId": request_id
            , "duplicate": 0
            , "browserOauth": browser_oauth
        }
        data.update(self.user_info)

        r = self.send_http(data)
        if str(r.get("statusCode")) == "0":
            return r
        elif str(r.get("statusCode")) == "-10003":
            print(f"login Err {json.dumps(r, ensure_ascii=False)}")
            exit()
        else:
            print(f"Fail {json.dumps(r, ensure_ascii=False)} ")
            exit()

    def login_click(self, driver):
        """在登录页面点击相应的元素"""
        selectors = [
            '//*[@data-test-id="customerName"]',
            '//*[@id="signInSubmit"]',
            '//*[@id="auth-signin-button"]',
            '//*[@id="continue"]',
        ]
        # 遍历选择器列表，尝试查找并点击元素
        for selector in selectors:
            try:
                time.sleep(2)
                element = WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.XPATH, selector)))
                # element = driver.find_element(By.XPATH, selector)
                element.click()
                print(f"登录页面点击 {selector}")
                break  # 找到并点击了元素，退出循环
            # except NoSuchElementException:
            except TimeoutException:
                continue

    def open_launcher_page(self, driver, launcher_page):
        driver.get(launcher_page)
        # driver.get(
        #     'https://sellercentral.amazon.com/home?ref_=xx_swlang_head_xx&mons_sel_locale=zh_CN&languageSwitched=1')
        time.sleep(5)
        if driver.title == '亚马逊 登录' or driver.title == 'Amazon 登入' or driver.title == 'Amazon Sign In':
            time.sleep(5)
            try:
                driver.find_element(By.XPATH, '//*[@id="auth-signin-button"]').click()
                driver.find_element(By.XPATH, '//*[@id="signInSubmit"]').click()
            except Exception:
                pass
        if driver.title == '两步验证' or driver.title == 'Two-Step Verification' or driver.title == '二步驟驗證':
            time.sleep(8)
            driver.find_element(By.XPATH, '//*[@id="auth-signin-button"]').click()
        if driver.title == '亚马逊':
            print("成功打开店铺主页")

    def open_ip_check(self, driver, ip_check_url):
        """
        打开ip检测页检测ip是否正常
        :param driver: driver实例
        :param ip_check_url ip检测页地址
        :return 检测结果
        """
        try:
            driver.get(ip_check_url)
            driver.find_element(By.XPATH, '//button[contains(@class, "styles_btn--success")]')
            return True
        except NoSuchElementException:
            print("未找到ip检测成功元素")
            return False
        except Exception as e:
            print("ip检测异常:" + traceback.format_exc())
            return False

    def open_one_store(self, store_id):
        ret_json = self.open_store(store_id)
        store_id = ret_json.get("browserOauth")
        if store_id is None:
            store_id = ret_json.get("browserId")
        # 使用驱动实例开启会话
        driver = self.get_driver(ret_json)
        if driver is None:
            # print(f"=====关闭店铺：{store_name}=====")
            self.close_store(store_id)
        # 获取ip检测页地址
        ip_check_url = ret_json.get("ipDetectionPage")
        if not ip_check_url:
            print("ip检测页地址为空，请升级紫鸟浏览器到最新版")
            driver.quit()
            # print(f"=====关闭店铺：{store_name}=====")
            self.close_store(store_id)
            exit()
        # 执行脚本
        # 设置元素查找等待时间-全局隐式等待
        driver.implicitly_wait(10)
        ip_usable = self.open_ip_check(driver, ip_check_url)
        print(ret_json.get("launcherPage"))
        if ip_usable:
            self.open_launcher_page(driver, ret_json.get("launcherPage"))
            # 打开店铺平台主页后进行后续自动化操作
            return ret_json
        else:
            print("ip检测不通过，请检查")
            return False

    def get_exit(self):
        data = {"action": "exit", "requestId": str(uuid.uuid4())}
        data.update(self.user_info)
        self.send_http(data)

    def get_marketplace_id(self, driver):
        page_source = driver.page_source
        soup = BeautifulSoup(page_source, 'html.parser')
        script_tags = soup.find_all('script')
        for script in script_tags:
            if script.string and 'ue_mid' in script.string:
                match = re.search(r"ue_mid\s*=\s*'([^']*)'", script.string)
                if match:
                    marketplace_id = match.group(1)
                    print("页面获取到的marketplace_id:", marketplace_id)
                    return marketplace_id

    def get_merchant_id(self, driver):
        page_source = driver.page_source
        soup = BeautifulSoup(page_source, 'html.parser')
        script_tag = soup.find('script', id='KPITOOLBAR_CHANNEL_PROPS')
        if script_tag:
            json_data = json.loads(script_tag.string)
            merchant_ids = set()
            for card in json_data.get("cards"):
                if card.get('cardType') == 'KPI_CARD_ORDERS':
                    # 提取regionalOpenOrdersMap中的数据
                    data = card['cardPayload']['data']['regionalOpenOrdersMap']
                    for region in data.values():
                        for market in region['merchantMarketplaceOpenOrdersList']:
                            if market['merchantID']:
                                print("找到的merchant_id:", market['merchantID'])
                                return market['merchantID']
        else:
            print("未找到KPITOOLBAR数据")
            return []

    def check_merchant_id(self, browserOauth):
        mysql_utils = MysqlUtils()
        merchant_id = mysql_utils.get_merchant_id(browserOauth)
        return merchant_id

    def check_marketplace_id(self, browserOauth):
        mysql_utils = MysqlUtils()
        marketplace_id = mysql_utils.get_marketplace_id(browserOauth)
        return marketplace_id

    def amz_designate_store_login(self, store_id, store_name, country="美国"):
        print(f"=====打开店铺：{store_name}=====")
        print(store_id)
        ret_json = self.open_one_store(store_id)
        driver = self.get_driver(ret_json)
        sleep(5)
        print("等待5秒检测页面元素")
        page_merchant_id = self.get_merchant_id(driver)
        page_marketplace_id = self.get_marketplace_id(driver)
        merchant_id = self.check_merchant_id(store_id)
        print("根据店铺id获取到的 merchant_id为：{}".format(merchant_id))
        if not page_merchant_id == merchant_id:
            print("{}检查不通过".format(merchant_id))
            return False
        else:
            print("{}检查通过".format(merchant_id))
            self.switch_sites(driver, country)
        marketplace_id = self.check_marketplace_id(store_id)
        if page_marketplace_id == marketplace_id:
            print("{}店铺检测通过！！！".format(store_name))
            return driver
        else:
            print("{}检测未通过, 关闭店铺首页".format(store_name))

    def switch_sites(self, driver, country):
        try:
            driver.find_element(By.XPATH, "//div[@id='dropdown-account-switcher-container']").click()
            time.sleep(3)
            driver.find_element(By.XPATH,
                                '//*[@id="dropdown-account-switcher-container"]/div/div[2]/div[2]/div/div').click()
            time.sleep(1)
            driver.find_element(By.XPATH, f"//div[@title='{country}']").click()
            print("店铺切换成功！")
        except Exception as e:
            print(e)
